/**
 * Copyright 2017 orivil Authors. All rights reserved.
 * Use of this source code is governed by a MIT-style
 * license that can be found at https://mit-license.org.
 */

package session

import (
	"time"
	"os"
	"gitee.com/tugoer/log"
	"path/filepath"
	"io/ioutil"
	"fmt"
)

var DefaultStorage Storage

// 持久存储器接口
type Storage interface {
	// 创建及更新 session 数据到持久存储器中。
	Save(id string, data []byte) error

	// 从持久存储器中删除 session 数据。
	Delete(id string) error

	// 根据过期时间从持久存储器中读取所有未过期的 session 数据
	ReadAll(expire time.Duration) (data map[string][]byte, err error)
}

// 文件存储器，实现了 Storage 接口
type FileStorage struct {
	dir string
}

func (fs *FileStorage) ReadAll(expire time.Duration) (data map[string][]byte, err error) {
	info, err := ioutil.ReadDir(fs.dir)
	if err != nil {
		return nil, err
	}
	data = make(map[string][]byte, len(info))
	now := time.Now()
	for _, info := range info {
		if !info.IsDir() {
			uuid := info.Name()
			filename := fs.filename(uuid)
			if now.After(info.ModTime().Add(expire)) {
				// 删除过期的数据
				err = os.Remove(filename)
				if err != nil {
					return nil, fmt.Errorf("remove expired session file [%s] got error: %s", filename, err)
				}
			} else {
				bytes, err := ioutil.ReadFile(filename)
				if err != nil {
					return nil, fmt.Errorf("read session file [%s] got error: %s", filename, err)
				}
				data[uuid] = bytes
			}
		}
	}
	return data, nil
}

func NewFileStorage(dir string) *FileStorage {
	err := os.MkdirAll(dir, 0666)
	if err != nil {
		log.Danger.Panicf("make session dir got error:%v", err)
	}
	return &FileStorage{dir: dir}
}

func (fs *FileStorage) Save(id string, data []byte) error {
	if len(data) > 0 {
		err := ioutil.WriteFile(fs.filename(id), data, 0666)
		return err
	}
	return nil
}

func (fs *FileStorage) filename(id string) string {
	return filepath.Join(fs.dir, id)
}

func (fs *FileStorage) Delete(id string) error {
	return os.Remove(fs.filename(id))
}